﻿using RM.BasicLibrary.Requests;
using RM.BasicLibrary.Resposes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RM.BasicLibrary.Transfers.TCP
{
    public class TcpServer : ITcp
    {
        private int receiveSize = 1024 * 1024 * 50;
        private int watchConnectInterval = 1000;
        private string HeartPag = "HeartPag";
        private Socket socket { get; set; }//负责监听客户端的套接字
        /// <summary>
        /// 在线客服端
        /// </summary>
        public List<Socket> ClientsLine { get; set; } = new List<Socket>();
        /// <summary>
        /// 运行中的任务客服端
        /// </summary>
        private Dictionary<CancellationTokenSource, Socket> RunTaskDic = new Dictionary<CancellationTokenSource, Socket>();
        /// <summary>
        /// 客服端总集合
        /// </summary>
        private List<Socket> Clients { get; set; } = new List<Socket>();
        public IPEndPoint Port { get; set; }

        private bool IsWatchReceive { get; set; } = false;

        public TcpServer()
        {

        }
        public void Connect(string ip = null, int port = 11000, Action<Socket> connectedHandler = null)
        {
            port.NotNull();
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint point = new IPEndPoint(IPAddress.Any, port);
            socket.Bind(point);
            socket.Listen(20);
            Task.Run(() =>
            {
                Socket connection = null;
                while (true)  //持续不断监听客户端发来的请求   
                {
                    Root.BasicIns.ExFilter.Execute(() =>
                    {
                        connection = socket.Accept();
                    });
                    if (!ClientsLine.Any(x => x.RemoteEndPoint == connection.RemoteEndPoint))
                    {
                        Clients.Add(connection);
                        ClientsLine.Add(connection);    //添加客户端信息
                        connectedHandler?.Invoke(connection);
                    }
                }
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="action">消息处理</param>
        public void WatchReceive<TRespose, TRequest>(Action<TRespose, TRequest, Socket> receiveCmdHandler)
     where TRespose : class
            where TRequest : class
        {
            IsWatchReceive = true;

            Task.Run(() =>
            {
                while (true)
                {
                    foreach (var x in ClientsLine.ToArray())
                    {
                        if (x == null) continue;
                        var cts = new CancellationTokenSource(); //增加取消消息源
                        if (!RunTaskDic.Any(y => y.Value.RemoteEndPoint == x.RemoteEndPoint))
                        {
                            var task = Task.Run(() => Receive(x, receiveCmdHandler, cts.Token), cts.Token);
                            RunTaskDic.Add(cts, x);
                        }
                    }
                    Thread.Sleep(watchConnectInterval);
                }
            });
            AutoStopTask();
        }
        public void WatchReceive(Action<byte[], Socket> receiveCmdHandler)
        {
            IsWatchReceive = true;

            Task.Run(() =>
            {
                while (true)
                {
                    foreach (var x in ClientsLine.ToArray())
                    {
                        if (x == null) continue;
                        var cts = new CancellationTokenSource(); //增加取消消息源
                        if (!RunTaskDic.Any(y => y.Value.RemoteEndPoint == x.RemoteEndPoint))
                        {
                            var task = Task.Run(() => Receive(x, receiveCmdHandler, cts.Token), cts.Token);
                            RunTaskDic.Add(cts, x);
                        }
                    }
                    Thread.Sleep(watchConnectInterval);
                }
            });
            AutoStopTask();
        }
        public void WatchReceive(Action<string, Socket> receiveCmdHandler)
        {
            IsWatchReceive = true;

            Task.Run(() =>
            {
                while (true)
                {
                    foreach (var x in ClientsLine.ToArray())
                    {
                        if (x == null) continue;
                        var cts = new CancellationTokenSource(); //增加取消消息源
                        if (!RunTaskDic.Any(y => y.Value.RemoteEndPoint == x.RemoteEndPoint))
                        {
                            var task = Task.Run(() => Receive(x, receiveCmdHandler, cts.Token), cts.Token);
                            RunTaskDic.Add(cts, x);
                        }
                    }
                    Thread.Sleep(watchConnectInterval);
                }
            });
            AutoStopTask();
        }
        private void AutoStopTask()
        {
            Task.Run(() =>
            {
                while (true)
                {
                    //SendHeartPag();
                    RunTaskDic.Where(x => !ClientsLine.Contains(x.Value)).ToList().ForEach(x =>
                     {
                         x.Key.Cancel();
                     });
                    Thread.Sleep(watchConnectInterval);
                }
            });
        }
        private void SendHeartPag()
        {
            Send(new Request() { Cmd = "HeartPag" });
        }
        private void Receive(Socket socketclientpara, Action<byte[], Socket> receiveCmdHandler, CancellationToken cancelToken)
        {
            while (true)
            {
                if (cancelToken.IsCancellationRequested)
                {
                    if (RunTaskDic.Any(y => y.Value.RemoteEndPoint == socketclientpara.RemoteEndPoint))
                        RunTaskDic.Remove(RunTaskDic.Single(y => y.Value.RemoteEndPoint == socketclientpara.RemoteEndPoint).Key);
                    return;
                }
                Root.BasicIns.ExFilter.Execute(() =>
                {
                    //创建一个内存缓冲区 其大小为1024*1024字节  即1M   
                    byte[] arrServerRecMsg = new byte[receiveSize];
                    //将接收到的信息存入到内存缓冲区,并返回其字节数组的长度  
                    int length = socketclientpara.Receive(arrServerRecMsg);
                    //将机器接受到的字节数组转换为人可以读懂的字符串   
                    string strRevMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);
                    if (strRevMsg.Contains(HeartPag))
                    {
                        if (!ClientsLine.Any(x => x.RemoteEndPoint == socketclientpara.RemoteEndPoint))
                            ClientsLine.Add(socketclientpara);
                        return;
                    }
                    receiveCmdHandler?.Invoke(arrServerRecMsg as byte[], socketclientpara);
                });
            }
        }
        private void Receive(Socket socketclientpara, Action<string, Socket> receiveCmdHandler, CancellationToken cancelToken)
        {
            while (true)
            {
                if (cancelToken.IsCancellationRequested)
                {
                    if (RunTaskDic.Any(y => y.Value.RemoteEndPoint == socketclientpara.RemoteEndPoint))
                        RunTaskDic.Remove(RunTaskDic.Single(y => y.Value.RemoteEndPoint == socketclientpara.RemoteEndPoint).Key);
                    return;
                }
                Root.BasicIns.ExFilter.Execute(() =>
                {
                    //创建一个内存缓冲区 其大小为1024*1024字节  即1M   
                    byte[] arrServerRecMsg = new byte[receiveSize];
                    //将接收到的信息存入到内存缓冲区,并返回其字节数组的长度  
                    int length = socketclientpara.Receive(arrServerRecMsg);
                    //将机器接受到的字节数组转换为人可以读懂的字符串   
                    string strRevMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);
                    if (strRevMsg.Contains(HeartPag))
                    {
                        if (!ClientsLine.Any(x => x.RemoteEndPoint == socketclientpara.RemoteEndPoint))
                            ClientsLine.Add(socketclientpara);
                        return;
                    }
                    receiveCmdHandler?.Invoke(strRevMsg, socketclientpara);
                });
            }
        }
        ///   
        /// 接收客户端发来的信息    
        ///   
        ///客户端套接字对象  
        private void Receive<TRespose, TRequest>(Socket socketclientpara, Action<TRespose, TRequest, Socket> receiveCmdHandler, CancellationToken cancelToken)
    where TRespose : class
            where TRequest : class
        {
            while (true)
            {
                if (cancelToken.IsCancellationRequested)
                {
                    if (RunTaskDic.Any(y => y.Value.RemoteEndPoint == socketclientpara.RemoteEndPoint))
                        RunTaskDic.Remove(RunTaskDic.Single(y => y.Value.RemoteEndPoint == socketclientpara.RemoteEndPoint).Key);
                    return;
                }
                Root.BasicIns.ExFilter.Execute(() =>
                {
                    //创建一个内存缓冲区 其大小为1024*1024字节  即1M   
                    byte[] arrServerRecMsg = new byte[receiveSize];
                    //将接收到的信息存入到内存缓冲区,并返回其字节数组的长度  
                    int length = socketclientpara.Receive(arrServerRecMsg);
                    //将机器接受到的字节数组转换为人可以读懂的字符串   
                    string strRevMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);

                    TRespose respose = default(TRespose);
                    TRequest request = default(TRequest);
                    Root.BasicIns.ExFilter.Execute(() =>
                    {
                        respose = Root.BasicIns.JsonSerialize.Deserialize<TRespose>(strRevMsg) as TRespose;
                    });
                    Root.BasicIns.ExFilter.Execute(() =>
                    {
                        request = Root.BasicIns.JsonSerialize.Deserialize<TRequest>(strRevMsg) as TRequest;
                    });
                    if (request != null && (request is Respose) && (request as Respose).Msg == HeartPag)
                    {
                        if (!ClientsLine.Any(x => x.RemoteEndPoint == socketclientpara.RemoteEndPoint))
                            ClientsLine.Add(socketclientpara);
                        return;
                    }
                    receiveCmdHandler?.Invoke(respose, request, socketclientpara);
                });
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endSocket"></param>
        /// <param name="request"></param>
        public void Send<T>(Socket endSocket, T respose) where T : class
        {
            endSocket.NotNull();
            respose.NotNull();
            Root.BasicIns.ExFilter.Execute(() =>
            {
                string cmd = string.Empty;
                byte[] bytes = null;
                if (!(respose is byte || respose is byte[]))
                {
                    if (!(respose is string))
                        cmd = Root.BasicIns.JsonSerialize.Serialize(respose);
                    else
                        cmd = respose as string;
                    bytes = System.Text.Encoding.UTF8.GetBytes(cmd);
                }
                bytes = respose as byte[];
                ClientsLine.FirstOrDefault(x => x.RemoteEndPoint == endSocket.RemoteEndPoint).Send(bytes);

            }, () =>
            {
                if (ClientsLine.Any(x => x.RemoteEndPoint == endSocket.RemoteEndPoint))
                    ClientsLine.Remove(endSocket);
            }, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="endSocket"></param>
        /// <param name="request"></param>
        public void Send<T>(T respose) where T : class
        {
            respose.NotNull();
            Root.BasicIns.ExFilter.Execute(() =>
            {
                string cmd = string.Empty;
                byte[] bytes = null;
                if (!(respose is byte || respose is byte[]))
                {
                    if (!(respose is string))
                        cmd = Root.BasicIns.JsonSerialize.Serialize(respose);
                    else
                        cmd = respose as string;
                    bytes = Encoding.UTF8.GetBytes(cmd);
                }
                else bytes = respose as byte[];
                List<Socket> sockets = new List<Socket>();
                ClientsLine.ForEach(x =>
                {
                    try
                    {
                        x.Send(bytes);
                    }
                    catch (Exception)
                    {
                        sockets.Add(x);
                    }
                });
                sockets.Where(x => ClientsLine.Contains(x)).ToList().ForEach(x =>
                {
                    ClientsLine.Remove(x);
                });
            });
        }


        public void SetReceive(int receiveSize = 52428800, int watchConnectInterval = 1000)
        {
            this.watchConnectInterval = watchConnectInterval;
            this.receiveSize = receiveSize;
        }


    }

}
